package pl.prv.polanie.client.widgets.table;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pl.prv.polanie.client.Planner;
import pl.prv.polanie.client.dto.CSDeclarationDTO;
import pl.prv.polanie.client.dto.CSVAcademicTitleDTO;
import pl.prv.polanie.client.dto.CSVBuildingDTO;
import pl.prv.polanie.client.dto.CSVCalendarDayDTO;
import pl.prv.polanie.client.dto.CSVDeclarationDTO;
import pl.prv.polanie.client.dto.CSVLecturerDTO;
import pl.prv.polanie.client.dto.CSVPreferenceTypeDTO;
import pl.prv.polanie.client.dto.CSVRoomDTO;
import pl.prv.polanie.client.dto.CSVRoomTypeDTO;
import pl.prv.polanie.client.dto.CSVSemestersYearGroupsDTO;
import pl.prv.polanie.client.dto.CSVSubgroupDTO;
import pl.prv.polanie.client.dto.CSVSubgroupTypeDTO;
import pl.prv.polanie.client.dto.CSVSubjectDTO;
import pl.prv.polanie.client.dto.CSVSubjectEventDTO;
import pl.prv.polanie.client.dto.CSVSubjectNameDTO;
import pl.prv.polanie.client.dto.CSVSubjectTypeDTO;
import pl.prv.polanie.client.dto.CSVYearGroupNameDTO;
import pl.prv.polanie.client.dto.ICSDTO;
import pl.prv.polanie.client.dto.ICSVDTO;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.SourcesTableEvents;
import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.Widget;



/**
 * Kontrolka tabelki umozliwiajaca sortowanie. Korzysta z typow ICSVDTO i ICSDTO.
 * 
 * @author Janusz Prokulewicz
 * Created: Jun 5, 2008
 */
public class CustomTable extends Composite {
	
	private static final String STYLE_CUSTOM_TABLE = "customTable";
	private static final String STYLE_CUSTOM_TABLE__HEADER_ROW = "customTable-headerRow";
	private static final String STYLE_CUSTOM_TABLE__VALUE_ROW = "customTable-valueRow";
//	private static final String STYLE_CUSTOM_TABLE__VALUE_ROW_GRAY = "customTable-valueRowGray";
//	private static final String STYLE_CUSTOM_TABLE__VALUE_ROW_GREEN = "customTable-valueRowGreen";
//	private static final String STYLE_CUSTOM_TABLE__VALUE_ROW_RED = "customTable-valueRowRed";
	private static final String STYLE_HIGHLIGHTED_WIDGET = "customTable-highlightedWidget";
	private static final String STYLE_SELECTED_WIDGET = "customTable-selectedWidget";
	
	private static final String sortedAscIconUrl =  "./widgets-images/sorted_asc.png";
	private static final String sortedDescIconUrl = "./widgets-images/sorted_desc.png";

	private FlexTable mainFT = new FlexTable();
	
	
	/** W tej liscie obiekty sa w takiej samej kolejnosci w jakiej sa wyswietlone w kontrolce. */
	private List<ICSVDTO> csvDtos = new ArrayList<ICSVDTO>();
	//<Long id, clientSide CSSubjectDTO>
	private Map<Long, ICSDTO> csDtosMap = new HashMap<Long, ICSDTO>();
	
	//<Long>
	/** lista obiektow Long przechowujacych szerokosci kolumn w tabeli. Jesli null, szerokosc jest nieoreslona. */
	private List<Long> columnsWidths = new ArrayList<Long>();
	
	/** Indicates by which column table is sorted. If it equals -1, it means that table ii not sorted. */
	private int sortedByColumn = -1;
	
	/** Indicates in which direction table is sorted, if it is sorted. */
	private boolean sortedAsc;
	
	
	private int columnCount = -1;
	
	
//	private int highlightedRowIndex = -1;
	
	private ICSVDTO highlightedCSVDto = null;
	
	private ICSVDTO selectedCSVDto = null;
	
	/**
	 * wskazuje, czy kontrolka oczekuje na drugi click
	 * Jesli wiersz zostal wczesniej zaznaczony, a pozniej zostanie klikniety,
	 * to na jakis czas ta zmienna bedzie == true, a pozniej zostanie zamieniona na false przez timer.
	 *
	 * Jesli w tym czasie zotanie klikniety zaznaczony wiersz, pokazuje sie okienko do edycji calego SubjectEventa.
	 */
	private boolean waitingForSecondClickHighlighted;
	
	private boolean waitingForSecondClickNotHighlighted;
	
	
	private Timer waitingForSecondClickNotHighlightedTimer = new Timer() {
		//@Override
		public void run() {
			waitingForSecondClickNotHighlighted = false;
		}
	};
	
	private Timer waitingForSecondClickHighlightedTimer = new Timer() {
		//@Override
		public void run() {
			waitingForSecondClickHighlighted = false;
		}
	};	
	
	
	public CustomTable() {
		
		mainFT.setBorderWidth(1);
		mainFT.setCellPadding(0);
		mainFT.setCellSpacing(0);
		mainFT.addStyleName(STYLE_CUSTOM_TABLE);
		initWidget(mainFT);
//		addTableHeader();
		
//		loadData();
		
		mainFT.addTableListener(new TableListener() {
			public void onCellClicked(SourcesTableEvents sender, int row, int cell) {
				if (row == 0) {
					int prevSortedColumn = sortedByColumn;
					
					//kliknieto na posortowana kolumne
					if (sortedByColumn == cell) {
						sortedAsc = !sortedAsc;
						sortByColumn(cell, sortedAsc, prevSortedColumn);						
					} else {
						sortedByColumn = cell;
						sortedAsc = true;
						sortByColumn(cell, sortedAsc, prevSortedColumn);
					}
				} else {
					//Planner.log(".onCellClicked: " + "wybieram wiersz na widoku: " + row);
					if (selectedCSVDto != null && getDtoIdByRow(row) == selectedCSVDto.getId()) {
						ICSVDTO csv = (ICSVDTO)csvDtos.get(row-1);
						Widget clickedW = mainFT.getWidget(row, cell);
						runOnClickSelectedRow(row, cell, csv, clickedW);
					} else {
						setSelectedOneRow(row);
//						highlightOneRow(row);
					}
				}
			}
		});
	}
	
	
	/**
	 * Zwraca numer id dto skojarzonego z wierszem w tabeli.
	 * @param row
	 * @return -1, gdy podany wiersz == 0.
	 */
	public long getDtoIdByRow(int row) {
		if (row == 0) {
			return -1;
		} else {
			ICSVDTO csv = (ICSVDTO)csvDtos.get(row-1);
			return csv.getId();
		}
	}
	
	public ICSDTO getCSDtoByID (long id) {
		return (ICSDTO)csDtosMap.get(new Long(id));
	} 
	
	public void setColumnWidth(int colIndex, long width) {
		mainFT.getColumnFormatter().setWidth(colIndex, width+"px");
		
//		if (colIndex >= getColumnsCount()) {
//			Planner.log("CustomTable.setColumnWidth: " + "colIndex zbyt duzy!");
//			return;
//		}
//		
//		//zakladamy, ze szeroksc jest w lisscie
//		Long colWidth = (Long)columnsWidths.get(colIndex);
//		if (colWidth != null) {
//			Planner.log("CustomTable.setColumnWidth: " + "dotychczasowa szerokosc: " + colWidth);
//		} else {
//			Planner.log("CustomTable.setColumnWidth: " + "nie bylo ustawionej wczesniej szerokosci");
//		}
//		
//		
//		columnsWidths.remove(colIndex);
//		columnsWidths.add(colIndex, new Long(width));
//		
//		
//		//zmiana rozmiaru wszystkich komorek w kolumnie
//		for (int i = 0; i < mainFT.getRowCount(); i++) {
//			Widget w = mainFT.getWidget(i, colIndex);
//			w.setWidth(width + "px");
//		}
	}
	
	
	
	private int getColumnsCount() {
		return mainFT.getCellCount(0);
	}
	
	public void addHeaderColumn(String columnTitle, int width) {
		addHeaderColumn(columnTitle, null, width);
		
	}
	
	/**
	 * Dodaje nowa kolumne do tabeli.
	 * @param columnTitle
	 * @param width szerokosc kolumny. Gdy -1, szerokosc nie bedzie ustawiona i bedzie dopasowana do najszerszego elementu.
	 */
	public void addHeaderColumn(String columnTitle, String tooltipText, int width) {
		int column = 0;
		
		if (mainFT.getRowCount() > 0) {
			column = mainFT.getCellCount(0);
		}
		
		
		HTML headerColHTML = new HTML(columnTitle);
		
		if (tooltipText != null) {
			headerColHTML.setTitle(tooltipText);
		}
		
		
		if (width == -1) {
			columnsWidths.add(null);
		} else {
			columnsWidths.add(new Long (width));
			headerColHTML.setWidth(width + "px");
		}
		mainFT.getRowFormatter().addStyleName(0, STYLE_CUSTOM_TABLE__HEADER_ROW);
		
//		headerColHTML.addStyleName(STYLE_CUSTOM_TABLE__HEADER_ROW);
		
		mainFT.setWidget(0, column, headerColHTML);
	}

//	private void addTableHeader() {
//		Label l0 = new Label (" ");
//		
//		Label l1 = new Label ("subject");
//		Label l1 = new Label ("subject");
//		Label l1 = new Label ("subject");
//		Label l1 = new Label ("subject");
//		
//		
//		STYLE_CUSTOM_TABLE__HEADER_ROW
//		
//		
//		mainFT.setWidget(0, 0, new Label(" ") );
//		mainFT.setWidget(0, 1, new Label("subject") );
//		mainFT.setWidget(0, 2, new Label("lecturer") );
//		mainFT.setWidget(0, 3, new Label("room") );
//		mainFT.setWidget(0, 4, new Label("subgroup") );
//	}
	
	/**
	 * @param row 0 for header row, For first row with data it equals 1.
	 */
	private void removeHighlightingFromRow(int row) {
		if (row == 0) return;
		highlightRowImpl(row, false);
		
//		//you cant highlight header row
//		if (row == 0) return;
//		
//		if (highlightedCSVDto != null) {
//			int highlightedRowIndex = csvDtos.indexOf(highlightedCSVDto);
//			
//			if (highlightedRowIndex != -1) {
//				highlightRowImpl(highlightedRowIndex + 1, false);
//			}
//			
//			highlightedCSVDto = null;
//		}
//
////		runOnHighlightingRow(highlightedCSVDto);
	}
	
	/**
	 * @param row 0 for header row, For first row with data it equals 1.
	 */
	private void highlightOneRow(int row) {
		//you cant highlight header row
		if (row == 0) return;
		
		if (highlightedCSVDto != null) {
			int highlightedRowIndex = csvDtos.indexOf(highlightedCSVDto);
			
			if (highlightedRowIndex != -1) {
				highlightRowImpl(highlightedRowIndex + 1, false);
			}
		}

		highlightedCSVDto = (ICSVDTO)csvDtos.get(row-1);
		
		highlightRowImpl(row, true);
		
		runOnHighlightingRow(highlightedCSVDto);
	}
	
	
	
	/**
	 * Zaznacza wiersz. Jesli byl wczesniej zaznaczony inny, to go najpierw odznacza.
	 * @param row 0 for header row, For first row with data it equals 1.
	 */
	private void setSelectedOneRow(int row) {
		//
		waitingForSecondClickNotHighlighted = true;
		waitingForSecondClickNotHighlightedTimer.schedule(200);
		
		
		//you cant highlight header row
		if (row == 0) return;
		
		removeSelectionFromSelectedRow();

		//zaznaczenie nowego, innego wiersza
		selectedCSVDto = (ICSVDTO)csvDtos.get(row-1);
		setSelectedRowImpl(row, true);
		
		runOnSelectRow(selectedCSVDto);
	}


	/**
	 * 
	 */
	public void removeSelectionFromSelectedRow() {
		//odznaczenie poprzednio wybranego wiersza
		if (selectedCSVDto != null) {
			int selectedRowIndex = csvDtos.indexOf(selectedCSVDto);
			selectedCSVDto.setHighlighted(false);
			
			if (selectedRowIndex != -1) {
				setSelectedRowImpl(selectedRowIndex + 1, false);
			}
		}
	}
	
	/**
	 * Podswietla wiersz skojarzony z dto o podanym id.
	 * @param id
	 */
	public void setSelectedRowByID(long id) {
		for (int i = 0; i < csvDtos.size(); i++) {
			ICSVDTO csvDto = (ICSVDTO)csvDtos.get(i);
			if (csvDto != null && csvDto.getId() == id) {
				setSelectedOneRow(i+1);
				return;
			}
		}
	}
	
	/**
	 * Podswietla wiersz skojarzony z dto o podanym id.
	 * @param id
	 */
	public void highlightRowByID(long id) {
		for (int i = 0; i < csvDtos.size(); i++) {
			ICSVDTO csvDto = (ICSVDTO)csvDtos.get(i);
			if (csvDto != null && csvDto.getId() == id) {
				highlightOneRow(i+1);
				return;
			}
			
		}
	}
	
	/**
	 * Usuwa podswietlenie z wiersza skojarzonego z dto o podanym id.
	 * @param id
	 */
	public void removeHighlightingFromRowByID(long id) {
		for (int i = 0; i < csvDtos.size(); i++) {
			ICSVDTO csvDto = (ICSVDTO)csvDtos.get(i);
			if (csvDto != null && csvDto.getId() == id) {
				removeHighlightingFromRow(i+1);
				return;
			}
			
		}
	}
	
	/**
	 * row -> liczac od zera na widoku (wiersz naglowkowy == 0)
	 * @param row
	 */
	private void highlightRowImpl(int row, boolean addHighlighting) {
//		Planner.log("CustomTable.highlightRowImpl: " + "row: " + row + "csvDtos.size " + csvDtos.size());
		
		ICSVDTO csvSE = (ICSVDTO)csvDtos.get(row-1);
		if (addHighlighting) {
			csvSE.setHighlighted(true); 
		} else {
			csvSE.setHighlighted(false);
		}
		
		for (int i = 0; i < mainFT.getCellCount(row); i++) {
			Widget w = mainFT.getWidget(row, i);
			if (addHighlighting) {
				w.addStyleName(STYLE_HIGHLIGHTED_WIDGET);
			} else {
				w.removeStyleName(STYLE_HIGHLIGHTED_WIDGET);
			}
		}
	}
	
	
	
	
	
	
	/**
	 * Zaznacza na kontrolce swiersz (dodaje style + ustawia jako selectedCSVDto).
	 * row -> liczac od zera na widoku (wiersz naglowkowy == 0)
	 * @param row
	 */
	private void setSelectedRowImpl(int row, boolean addSelection) {
//		Planner.log("CustomTable.setSelectedRowImpl: " + "row: " + row + "csvDtos.size " + csvDtos.size());
		if (row <= 0) {
			return;
		}
		
		
		ICSVDTO csvSE = (ICSVDTO)csvDtos.get(row-1);
		if (addSelection) {
			selectedCSVDto = csvSE;
		} else {
			selectedCSVDto = null;
		}
		
		for (int i = 0; i < mainFT.getCellCount(row); i++) {
			Widget w = mainFT.getWidget(row, i);
			if (addSelection) {
				w.addStyleName(STYLE_SELECTED_WIDGET);
			} else {
				w.removeStyleName(STYLE_SELECTED_WIDGET);
			}
		}
	}
	
	public void addRow(ICSDTO csDto, ICSVDTO csvDto) {
		addRow(csDto, csvDto, -1);
	}
	
	/**
	 * Dodawanie nowego wiersza. Funkcja wykorzystywana zarowno podczas dodawania
	 * calkowicie nowego wiersza jak i przy przebudowywaniu kontrolki podczas sortowania.  
	 * @param csDto jesli == null, przebudowywany jest jedynie widok
	 * @param csvDto
	 * @param index index, pod ktorym ma zostac wstawiony nowy wiersz (0 => pierwzy wiersz pod wierszem naglowkowym w tabeli)
	 * 		jesli = -1, to wstawiamy wiersz na koniec 
	 */
	public void addRow(ICSDTO csDto, ICSVDTO csvDto, int index) {
//		Planner.log("CustomTable.addRow: " + "index: " + index + ", cs " + csDto + ", csv " + csvDto);
		
		//dodawanie calkowicie nowego wiersza
		if (csDto != null) {
			if (index == -1) {
				csvDtos.add(csvDto);
			} else {
				csvDtos.add(index, csvDto);
			}
			csDtosMap.put(new Long(csDto.getId()), csDto);
		}

		
		//dodanie nowego wiersza do widoku
		int row = mainFT.getRowCount();
		
		if (index != -1) {
			row = index+1;
			mainFT.insertRow(row);
		}

//		Planner.log("CustomTable.addRow: " + "POD WIERSZ " + row);
 
		for (int i = 0; i < columnCount; i++) {
			String text = "" + csvDto.getField(i);
			if (text.equals("")) {
				text = "&nbsp;"; 
			}
			HTML value = new HTML(text);
			value.addStyleName(STYLE_CUSTOM_TABLE__VALUE_ROW);
			mainFT.setWidget(row, i, value);
		}

		
		if (selectedCSVDto != null && selectedCSVDto.getId() == csvDto.getId()) {
			setSelectedRowImpl(row, true);
		}
	}
	
	
	/**
	 * Usuwa wiersz z tabeli (zarowno z widoku jak i pod spodem). <br>
	 * Jezeli byl zaznaczony, to najpierw go odznacza. 
	 * @param csvDto
	 */
	public void removeRow(ICSVDTO csvDto) {
//		Planner.log("CustomTable.addRow: " + "index: " + index + ", cs " + csDto + ", csv " + csvDto);

		int rowIndex = csvDtos.indexOf(csvDto);
		Planner.log("CustomTable.removeRow: " + "usuwam wiersz o indeksie " + rowIndex);
		
		//usuniecie zaznaczenia z wiersza
		if (isRowSelectedWithGivenDTO(csvDto)) {
			setSelectedRowImpl(rowIndex, false);
		}

		
		
		//usuniecie obiektow z obu kolekcji
		csvDtos.remove(csvDto);
		csDtosMap.remove(new Long(csvDto.getId()));
		
		//usuniecie wiersza z widoku
		mainFT.removeRow(rowIndex+1);
	}

	
	
	private boolean isRowSelectedWithGivenDTO(ICSVDTO csvDto) {
		return getSelectedCSVDto() != null && getSelectedCSVDto().getId() == csvDto.getId();
	}
	
	

	public long getColumnWidth(int colIndex) {
		Long colWidth = (Long)columnsWidths.get(colIndex);
		
		if (colWidth != null) {
			return colWidth.longValue();
		} else {
			return -1;
		}
	}
	
	
	
	/**
	 * Dodaje nowy wiersz (obowiazkowo musi miec przypisany id) do tabeli lub aktualizuje istniejacy o identycznym id.
	 * @param csDto
	 * @param csvDto
	 */
	public void addOrUpdateDTOInTable(ICSDTO csDto, ICSVDTO csvDto) {
		//poszukac o tym id rekordu
		//usunac wiersz z widoku i z kolekcji
		//wstawic nowy wiersz uzywajac kontrolki widoku
		
		
		//numer rekordu z danymi (dla pierwszego w kolejnosci = 0)
		int recordNo = -1;
		
		
		//szuka wiersza skojarzonego z DTO o podanym id i indeks zapisuje pod recordNo 
		for (int i = 0; i < csvDtos.size(); i++) {
			ICSVDTO csv = (ICSVDTO)csvDtos.get(i);
			if (csv != null && csv.getId() == csDto.getId()) {
				recordNo = i;
				break;
			}
		}

		
		
		if (recordNo == -1) {
//			Planner.log("CustomTable.saveOrUpdateSubjectEventInTable: " + "nie znaleziono rekordu o id " + csDto.getId());

			//dodac nowy wiersz
			
			addRow(csDto, csvDto, recordNo);
//			csvDtos.add(csvDto);
//			csDtosMap.put(new Long(csDto.getId()), csDto);
		} else {
//			Planner.log("CustomTable.saveOrUpdateSubjectEventInTable: " + " znaleziono wiersz pod indeksem (widok) " + (recordNo+1) );
			//wiersz o id istnial w tabeli -> usuwamy go i wstawiamy nowy
			csvDtos.remove(recordNo);
			mainFT.removeRow(recordNo+1);
			
			csvDtos.add(recordNo, csvDto);
			csDtosMap.put(new Long(csDto.getId()), csDto);	
			addRow(null, csvDto, recordNo);
		}
		
	}
	
//	public void removeRowFromTable(ICSDTO csDto, ICSVDTO csvDto) {
//		//poszukac o tym id rekordu
//		//usunac wiersz z widoku i z kolekcji
//		//wstawic nowy wiersz uzywajac kontrolki widoku
//		
//		
//		//numer rekordu z danymi (dla pierwszego w kolejnosci = 0)
//		int recordNo = -1;
//		
//		
//		//szuka wiersza skojarzonego z DTO o podanym id i indeks zapisuje pod recordNo 
//		for (int i = 0; i < csvDtos.size(); i++) {
//			ICSVDTO csv = (ICSVDTO)csvDtos.get(i);
//			if (csv != null && csv.getId() == csDto.getId()) {
//				recordNo = i;
//				break;
//			}
//		}
//
//		
//		
//		if (recordNo == -1) {
////			Planner.log("CustomTable.saveOrUpdateSubjectEventInTable: " + "nie znaleziono rekordu o id " + csDto.getId());
//
//			//dodac nowy wiersz
//			
//			addRow(csDto, csvDto, recordNo);
////			csvDtos.add(csvDto);
////			csDtosMap.put(new Long(csDto.getId()), csDto);
//		} else {
////			Planner.log("CustomTable.saveOrUpdateSubjectEventInTable: " + " znaleziono wiersz pod indeksem (widok) " + (recordNo+1) );
//			//wiersz o id istnial w tabeli -> usuwamy go i wstawiamy nowy
//			csvDtos.remove(recordNo);
//			mainFT.removeRow(recordNo+1);
//			
//			csvDtos.add(recordNo, csvDto);
//			csDtosMap.put(new Long(csDto.getId()), csDto);	
//			addRow(null, csvDto, recordNo);
//		}
//		
//	}

	
	
	
	
	public void sortByColumn(final int colIndex, final boolean asc, final int previouslySortedColumn ) {
		
		//posprzatac poprzednie zaznaczenie -> usunac strzalke wskazujaca na posortowanie
		if (previouslySortedColumn != colIndex && previouslySortedColumn != -1) {
			HTML html = (HTML)mainFT.getWidget(0, previouslySortedColumn);
			String label = html.getText();
			html.setHTML(label);
		}
		
		//ustawienie strzalek
		HTML html = (HTML)mainFT.getWidget(0, colIndex);
		String label = html.getText();
		if (asc) {
			html.setHTML(label + "<img style='margin-left: 5px;' src='" + sortedAscIconUrl + "' />");
		} else {
			html.setHTML(label + "<img style='margin-left: 5px;' src='" + sortedDescIconUrl + "' />");
		}
		
		
		Date d = new Date();
//		Planner.log("CustomTable.sortByColumn: start" + d);
		
		
		if (csvDtos.size() > 0) {
			ICSVDTO csv = ((ICSVDTO)csvDtos.get(0));
			Comparator comp = null;
			if (csv instanceof CSVLecturerDTO) {
				comp = CSVLecturerDTO.getComparator(colIndex);
			} else if (csv instanceof CSVAcademicTitleDTO) {
				comp = CSVAcademicTitleDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubgroupDTO) {
				comp = CSVSubgroupDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubjectEventDTO) {
				comp = CSVSubjectEventDTO.getComparator(colIndex);
			} else if (csv instanceof CSVCalendarDayDTO) {
				comp = CSVCalendarDayDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubjectNameDTO) {
				comp = CSVSubjectNameDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubjectDTO) {
				comp = CSVSubjectDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubjectTypeDTO) {
				comp = CSVSubjectTypeDTO.getComparator(colIndex);
			} else if (csv instanceof CSVRoomTypeDTO) {
				comp = CSVRoomTypeDTO.getComparator(colIndex);
			} else if (csv instanceof CSVBuildingDTO) {
				comp = CSVBuildingDTO.getComparator(colIndex);
			} else if (csv instanceof CSVRoomDTO) {
				comp = CSVRoomDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSubgroupTypeDTO) {
				comp = CSVSubgroupTypeDTO.getComparator(colIndex);
			} else if (csv instanceof CSVYearGroupNameDTO) {
				comp = CSVYearGroupNameDTO.getComparator(colIndex);
			} else if (csv instanceof CSVDeclarationDTO) {
				comp = CSVDeclarationDTO.getComparator(colIndex);
			} else if (csv instanceof CSVSemestersYearGroupsDTO) {
				comp = CSVSemestersYearGroupsDTO.getComparator(colIndex);
			} else if (csv instanceof CSVPreferenceTypeDTO) {
				comp = CSVPreferenceTypeDTO.getComparator(colIndex);
			}
			
//			Collections.sort(csvDtos, Comparators.getComparatorCSVSubjectEvent(colIndex));
			Collections.sort(csvDtos, comp);
			if (!asc) {
				Collections.reverse(csvDtos);
			}
		}
		d = new Date();
		
//		Planner.log("CustomTable.sortByColumn: stop" + d);
		
//		for (int i = 0; i < mainFT.getRowCount(); i++) {
//			mainFT.removeRow(0);
//		}
		
		for (int i = mainFT.getRowCount()-1; i > 0; i--) {
			mainFT.removeRow(i);
		}

		d = new Date();
//		Planner.log("CustomTable.sortByColumn: po wyczyszczeniu" + d);

		for (int i = 0; i < csvDtos.size(); i++) {
			ICSVDTO csvSE = (ICSVDTO) csvDtos.get(i);
			addRow(null, csvSE);
		}
		d = new Date();
//		Planner.log("CustomTable.sortByColumn: KONIEC " + d);
	}
	
	public void removeHighlightingFromRows() {
		if (highlightedCSVDto != null) {
			removeHighlightingFromRowByID(highlightedCSVDto.getId());
		}
	}
	
	/**
	 * Metoda uruchamiana w momencie podswietlenia ktoregos z wierszy.
	 */
	protected void runOnHighlightingRow(ICSVDTO csvDto) {}
	

	public void remove(Widget widget) {
		mainFT.remove(widget);
	}
	
	public void setWidget(int row, int column, Widget widget) {
		mainFT.setWidget(row, column, widget);
	}
	
	
	/**
	 * Metoda uruchamiana w momencie klikniecia na podswietlony juz wiersz.
	 */
	protected void runOnClickSelectedRow(int row, int column, ICSVDTO csvDto, Widget w) {
		if (waitingForSecondClickNotHighlighted) {
			waitingForSecondClickNotHighlighted = false;
			runOnDoubleClickOnNotSelectedRow(row, column, csvDto, w);
			Planner.log("CustomTable.runOnClickSelectedRow: " + "DOUBLE CLICK na not highlighted!");
		} else {
			//przpypadek, gdy wiersz byl wczesniej zaznaczony, ale dopero po chwili mamy niezalezny dwuklik
//			Planner.log("DRUGI PRZYPADEK");
			if (waitingForSecondClickHighlighted) {
//				Planner.log("DRUGI PRZYPADEK II");
				waitingForSecondClickHighlighted = false;
				Planner.log("CustomTable.runOnClickSelectedRow: " + "DOUBLE CLICK na highlighted!");
				runOnDoubleClickOnSelectedRow(row, column, csvDto, w);
			}
		}


		
		//
		waitingForSecondClickHighlighted = true;
		waitingForSecondClickHighlightedTimer.schedule(200);
		
		
	}
	
	/**
	 * Metoda odpalana w momencie DOUBLE CLICKA na wybrany wiersz. 
	 * @param csvDto
	 */
	protected void runOnDoubleClickOnSelectedRow(int row, int column, ICSVDTO csvDto, Widget w) {}
	

	/**
	 * Metoda odpalana w momencie DOUBLE CLICKA na niewybrany wiersz. 
	 * @param csvDto
	 */
	protected void runOnDoubleClickOnNotSelectedRow(int row, int column, ICSVDTO csvDto, Widget w) {}

	
	
	/**
	 * Metoda uruchamiana w momencie wybierania ktoregos z wierszy.
	 */
	protected void runOnSelectRow(ICSVDTO csvDto) {}


	public int getColumnCount() {
		return columnCount;
	}


	public void setColumnCount(int columnCount) {
		this.columnCount = columnCount;
	}

	public void setVerticalAlignment(int row, int column, HasVerticalAlignment.VerticalAlignmentConstant verticalAlignment) {
		mainFT.getCellFormatter().setVerticalAlignment(row, column, verticalAlignment);
	}


	public ICSVDTO getSelectedCSVDto() {
		return selectedCSVDto;
	}

	
	public CSDeclarationDTO getSelectedCSDto() {
		if (selectedCSVDto != null) {
			return (CSDeclarationDTO)getCSDtoByID(selectedCSVDto.getId());
		}
		return null;
	}

	
	public Map<Long, ICSDTO> getCsDtosMap() {
		return csDtosMap;
	}
	
	
//	public static void main(String[] args) {
//		List list = new ArrayList();
//		
////		for (int i = 0; i < 100; i++) {
////			long no = i;
////			long no2 = no % 10; 
////			CSSubjectEventDTO cs = new CSSubjectEventDTO(no, 1, (long)2, (long)2, (long)1, (long)1, (long)1, new Integer(660), new Integer(100));
////			CSVSubjectEventDTO csv = new CSVSubjectEventDTO(no, 2, "subject " + (no + no2), "room " + no, "subgroup " + no, "lect " + no,
////					"poniedzialek", new Integer(660), new Integer(100));
////			list.add(csv);
////		}
//		
//
//		CSVSubjectEventDTO csv1 = new CSVSubjectEventDTO(1, 2, "Matematyka", "W1", "subgroup 1", "Adam Nowak",
//				"poniedzialek", new Integer(660), new Integer(100));
//		CSVSubjectEventDTO csv2 = new CSVSubjectEventDTO(1, 2, "Jezyk Polski", "WA11", "subgroup 1", "Adam Nowak",
//				"poniedzialek", new Integer(660), new Integer(100));
//		CSVSubjectEventDTO csv3 = new CSVSubjectEventDTO(1, 2, "Religia", "W1", "subgroup 1", "Adam Nowak",
//				"poniedzialek", new Integer(660), new Integer(100));
//		CSVSubjectEventDTO csv4 = new CSVSubjectEventDTO(1, 2, "WF", "W1", "subgroup 1", "Adam Nowak",
//				"poniedzialek", new Integer(660), new Integer(100));
//		CSVSubjectEventDTO csv5 = new CSVSubjectEventDTO(1, 2, "Plastyka", "A0", "subgroup 1", "Adam Nowak",
//				"poniedzialek", new Integer(660), new Integer(100));
//
//		
//		list.add(csv1);
//		list.add(csv2);
//		list.add(csv3);
//		list.add(csv4);
//		list.add(csv5);
//
//		for (int i = 0; i < list.size(); i++) {
//			CSVSubjectEventDTO csv = (CSVSubjectEventDTO)list.get(i);
//			System.out.println("CustomTable.main(): " + i + " -> " + csv);
//		}
//		
//		Collections.sort(list, Comparators.getComparatorCSVSubjectEvent(CSVSubjectEventDTO.SORT_CONST__ROOM));
//		
//		System.out.println("POOOOOOO");
//		
//		for (int i = 0; i < list.size(); i++) {
//			CSVSubjectEventDTO csv = (CSVSubjectEventDTO)list.get(i);
//			System.out.println("CustomTable.main(): " + i + " -> " + csv);
//		}
//		
//	}
	

	
	
}
